package com.jlf.starter.advice.reactive;

import com.jlf.core.output.ResultWrapper;
import com.jlf.starter.advice.reactive.util.OutputTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.lang.NonNull;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 统一输出的封装
 * 由于系统有一个默认的 ResponseBodyResultHandler 的bean，本方法需要考虑覆盖系统默认的bean才能生效，
 * 通过查看ResponseBodyResultHandler的方法，发现该默认bean的order是100，因此，为了提高优先级，在构造
 * 方法中，把优先级设置为99，次方法存在风险，一旦默认的值变更了，需要跟进调整
 *
 * @author wujr
 * 2023/8/2
 * @version 1.0
 * 【变更历史】
 * [wujr 2023/8/2 1.0 新增]
 */
@Slf4j
public class OutputAdvice extends ResponseBodyResultHandler {
    private static final MethodParameter METHOD_PARAMETER_MONO_RESULT_WRAPPER;
    private static final ResultWrapper<Object> DEFAULT_OK_WRAPPER = ResultWrapper.DEFAULT_OK;

    static {
        try {
            // 获得 METHOD_PARAMETER_MONO_RESULT_WRAPPER 。其中 -1 表示 `#methodForParams()` 方法的返回值
            METHOD_PARAMETER_MONO_RESULT_WRAPPER = new MethodParameter(
                    OutputAdvice.class.getDeclaredMethod("methodForParams"), -1);
        } catch (NoSuchMethodException e) {
            log.error("[static][获取 METHOD_PARAMETER_MONO_RESULT_WRAPPER 时，找不都方法");
            throw new RuntimeException(e);
        }
    }

//    public OutputAdvice(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver) {
//        super(writers, resolver);
//        setOrder(99);
//    }

    public OutputAdvice(List<HttpMessageWriter<?>> writers, RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
        super(writers, resolver, registry);
        setOrder(99);
    }

    private static Mono<ResultWrapper<?>> methodForParams() {
        return null;
    }

    @Override
    public boolean supports(@NonNull HandlerResult result){
        return OutputTool.isSupported(result);
    }

    @Override
    @NonNull
    @SuppressWarnings("unchecked")
    public Mono<Void> handleResult(@NonNull ServerWebExchange exchange, @NonNull HandlerResult result) {
        Object returnValue = result.getReturnValue();
        Object body;

        // <1.1>  处理返回结果为 Mono 的情况
        if (returnValue instanceof Mono) {
            body = ((Mono<Object>) result.getReturnValue())
                    .map(OutputTool::wrapResult)
                    .defaultIfEmpty(DEFAULT_OK_WRAPPER);
            //  <1.2> 处理返回结果为 Flux 的情况
        } else if (returnValue instanceof Flux) {
            body = ((Flux<Object>) result.getReturnValue())
                    .collectList()
                    .map(OutputTool::wrapResult)
                    .defaultIfEmpty(DEFAULT_OK_WRAPPER);
            //  <1.3> 处理结果为其它类型
        } else {
            body = Mono.justOrEmpty(returnValue).map(OutputTool::wrapResult)
                    .defaultIfEmpty(DEFAULT_OK_WRAPPER);
        }
        return writeBody(body, METHOD_PARAMETER_MONO_RESULT_WRAPPER, exchange);
    }
}
